#pragma once

#include "Macros.h"
#include "InputTypes.h"
#include <cstdint>
#include <memory>
#include <string>
#include <filesystem>

struct GLFWwindow;

namespace SL
{
// struct KeyboardEvent;
// struct MouseEvent;
// struct GamepadEvent;
// struct GamepadState;

class SELAH_API Window
{
public:
    enum class WindowMode
    {
        Normal,
        Minimized,
        Fullscreen,
    };
    struct Desc
    {
        uint32_t width = 1280;                ///< The width of the client area size.
        uint32_t height = 720;                ///< The height of the client area size.
        std::string title = "Selah Sample";   ///< Window title.
        WindowMode mode = WindowMode::Normal; ///< Window mode. In full screen mode, width and height will be ignored.
        bool resizableWindow = true; ///< Allow the user to resize the window.
        bool enableVSync = false;    ///< Controls vertical-sync.
        bool seperateUI = true;      ///< UI is rendered in a seperate window.
    };

    class ICallbacks
    {
    public:
        virtual void handleWindowSizeChange() = 0;
        // virtual void handleRenderFrame() = 0;
        virtual void handleKeyboardEvent(const KeyboardEvent& keyEvent) = 0;
        virtual void handleMouseEvent(const MouseEvent& mouseEvent) = 0;
        virtual void handleGamepadEvent(const GamepadEvent& gamepadEvent) = 0;
        virtual void handleGamepadState(const GamepadState& gamepadState) = 0;
        virtual void handleDroppedFile(const std::filesystem::path& path) = 0;
    };

    static std::unique_ptr<Window> create(const Desc& desc, ICallbacks* pCallbacks);

    ~Window();

    void setWindowSize(uint32_t width, uint32_t height);
    void resize(uint32_t width, uint32_t height);
    void shutDown();
    bool shouldClose();
    void pollEvents();
    float2 getMouseScale() const { return m_mouse_scale; }

    GLFWwindow* getWindow() { return m_pWindow; }

private:
    friend class ApiCallbacks;
    Window(const Desc& desc, ICallbacks* pCallbacks);

    GLFWwindow* m_pWindow = nullptr;
    Desc m_desc;
    WindowMode m_mode;
    ICallbacks* mpCallbacks = nullptr;
    float2 m_mouse_scale{1.0f, 1.0f}; ///< Mouse scale for mouse position normalization
};
} // namespace SL